package se.ramfelt.psnfriends;

import java.util.ArrayList;
import java.util.Collections;

import java.util.List;

import org.apache.http.impl.client.DefaultHttpClient;

import com.flurry.android.FlurryAgent;
import com.github.droidfu.imageloader.ImageLoader;
import com.google.android.divideandconquer.Eula;

import se.ramfelt.psn.model.Friend;
import se.ramfelt.psn.model.PresenceFriendComparator;
import se.ramfelt.psn.web.us.UsPlaystationSite;
import se.ramfelt.psnfriends.R;
import se.ramfelt.psnfriends.model.web.FakePsnCommunicator;
import se.ramfelt.psnfriends.model.web.PsnCommunicator;
import se.ramfelt.psnfriends.util.RandomXorObfuscator;
import se.ramfelt.psnfriends.util.TextUtil;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
//import android.util.Log;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

public class FriendsListActivity extends ListActivity implements OnCancelListener, OnItemClickListener, Eula.OnEulaAgreedTo  {

    //private static final String LOG_TAG = "psn.activitylist";
    
    private static final int MESSAGE_STARTED = 0;
    private static final int MESSAGE_FINISED = 1;
    private static final int MESSAGE_STATUS = 2;
    private static final int MESSAGE_ERROR = 3;

    private static final int ACTIVITY_PREFERENCE_CODE = 0;

    private FriendAdapter listAdapter;
    private PsnCommunicator psnCommunicator;
    private Thread thread;	
    private long accountHashcode;
    
    private AlertDialog dialog;
    
    private final MessageHandler messageHandler = new MessageHandler();	
    private final PsnCommunicator.Listener communicatorListener = new PsnCommuniatorListener();

    private ArrayList<Friend> friendList = new ArrayList<Friend>();

	private UsPlaystationSite psnSite;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        ImageLoader.initialize(this);
        
        listAdapter = new FriendAdapter(this, R.layout.friend_list_row, friendList);
        setListAdapter(listAdapter);
        
        getListView().setOnItemClickListener(this);
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        FlurryAgent.onStartSession(this, Flurry.KEY);        
        Eula.show(this);
        	
    	initCommunicator();
    	
        if (((dialog == null) || (!dialog.isShowing())) && 
        		((psnSite!= null) && (!psnSite.isLoggedIn()))) {
            startThread();
        }
        FlurryAgent.onEvent("view.friends");
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        stopThread();
        if ((dialog != null) && dialog.isShowing()) {
        	dialog.dismiss();
        }
        FlurryAgent.onEndSession(this);
    }

	public void onEulaAgreedTo() {
		startActivityForResult(new Intent(FriendsListActivity.this, PreferencesActivity.class), ACTIVITY_PREFERENCE_CODE);
	}

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == ACTIVITY_PREFERENCE_CODE) {
            // Update network data
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
            String username = preferences.getString(getString(R.string.pref_account_username), "");
            String password = preferences.getString(getString(R.string.pref_account_password), "");
            
            if ((username.length() == 0) || (password.length() == 0)) {
                new AlertDialog.Builder(FriendsListActivity.this).
                    setMessage(R.string.pref_account_not_configured).
                    setIcon(android.R.drawable.ic_dialog_alert).
                    setPositiveButton(R.string.change, new OnClickListener() {						
                        public void onClick(DialogInterface dialog, int which) {
                            startActivityForResult(new Intent(FriendsListActivity.this, PreferencesActivity.class), ACTIVITY_PREFERENCE_CODE);
                        }
                    }).setNegativeButton(R.string.ignore, new OnClickListener() {						
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    }).create().show();
            } else {
                initCommunicator();
            }			
        }
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.friendslist, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_preferences:
            startActivityForResult(new Intent(FriendsListActivity.this, PreferencesActivity.class), ACTIVITY_PREFERENCE_CODE);
            return true;
        case R.id.menu_refresh:
            startThread();
            return true;
        case R.id.menu_about:
            try {
                new AlertDialog.Builder(this).setIcon(R.drawable.main).
                    setTitle(String.format("%s - %s", getString(R.string.app_name), getPackageManager().getPackageInfo(getPackageName(), 0).versionName)).
                    setMessage(R.string.app_about).
                    create().show();
            } catch (NameNotFoundException e) {
            }
        }
        return super.onOptionsItemSelected(item);
    }

    public void onCancel(DialogInterface arg0) {
        thread.interrupt();
    }

    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        new FriendDetailDialog(friendList.get((int) id), this).show();
    }
    
    private void stopThread() {
        if (thread != null) {
            if (thread.isAlive()) {
                thread.interrupt();
            }
            thread = null;
        }
    }
    
    private void startThread() {
        if ((thread == null) || (!thread.isAlive())) {
            if (psnCommunicator != null) {
                thread = new Thread(psnCommunicator);
                thread.start();
            }
        }
    }

	private void initCommunicator() {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        String username = preferences.getString(getString(R.string.pref_account_username), "");
        String password = preferences.getString(getString(R.string.pref_account_password), "");
        
        if ((username.length() != 0) && (password.length() != 0)) {
			long newAccountHashcode = new StringBuilder().append(username).append("==").append(password).toString().hashCode();
			if (newAccountHashcode != accountHashcode) {
			    accountHashcode = newAccountHashcode;
			    psnSite = new UsPlaystationSite(new DefaultHttpClient());
			    ImageLoader.setNetwork(psnSite);
			    psnCommunicator = new PsnCommunicator(psnSite, username,new RandomXorObfuscator(Eula.getAcceptedTime(this)).reverse(password), communicatorListener);
			}
        }
	}		
    
    public void setItems(List<Friend> items) {
        this.friendList.clear();
        this.friendList.addAll(items);
        Collections.sort(this.friendList, new PresenceFriendComparator());
        this.listAdapter.notifyDataSetChanged();
    }

    private final class MessageHandler extends Handler {
        @SuppressWarnings("unchecked")
        @Override
        public void handleMessage(final Message msg) {
            switch (msg.what) {
            case MESSAGE_STARTED:
                //Log.i(LOG_TAG, "Received STARTED message");
                dialog = ProgressDialog.show(FriendsListActivity.this, 
                        "", 
                        getString(R.string.status_psn_login), 
                        true, true, FriendsListActivity.this);
                break;
            case MESSAGE_FINISED:
                //Log.i(LOG_TAG, "Received FINISHED message");
                dialog.dismiss();
                setItems((List<Friend>) msg.obj);
                break;
            case MESSAGE_STATUS:
                //Log.i(LOG_TAG, "Received STATUS message: " + msg.arg1);
                dialog.setMessage(getString(msg.arg1));
                break;
            case MESSAGE_ERROR:
                //Log.i(LOG_TAG, "Received ERROR message");
                dialog.dismiss();
                Builder builder = new AlertDialog.Builder(FriendsListActivity.this).
                    setMessage(msg.arg1).
                    setTitle(R.string.error).
                    setIcon(android.R.drawable.ic_dialog_alert);
                switch (msg.arg1) {
                case R.string.status_psn_login_error:
                    builder = builder.setPositiveButton(R.string.change, new OnClickListener() {						
                        public void onClick(DialogInterface dialog, int which) {
                            startActivityForResult(new Intent(FriendsListActivity.this, PreferencesActivity.class), ACTIVITY_PREFERENCE_CODE);
                        }
                    }).setNegativeButton(R.string.ignore, new OnClickListener() {						
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
                    break;
                case R.string.status_psn_unexpected_error:
                    builder = builder.setPositiveButton(R.string.share, new OnClickListener() {
                        String errorClass;
                        String error;
                        {
                            Throwable throwable = (Throwable) msg.obj;
                            errorClass = throwable.getClass().getName();
                            error= throwable.getMessage();
                            if (throwable.getCause() != null) {
                                throwable = throwable.getCause();
                                error += " Cause:" + throwable.getClass().getName() + " '" + throwable.getMessage() + "'";
                            }
                        }
                        public void onClick(DialogInterface dialog, int which) {
                            //System.out.println(String.format("Sharing error with flurry. error=%s, errorClass=%s", error, errorClass));
                            FlurryAgent.onError("psncommunicator_unexpected_error", error, errorClass);
                        }
                    }).setNegativeButton(R.string.ignore, new OnClickListener() {						
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    });
                    break;
                }
                dialog = builder.create();
                dialog.show();
                break;
            }
        }
    }

    private final class PsnCommuniatorListener implements PsnCommunicator.Listener {
        public void onStarted(PsnCommunicator source) {
        	if (source == psnCommunicator) {
        		Message.obtain(messageHandler, MESSAGE_STARTED).sendToTarget();
        	}
        }

        public void onFinished(PsnCommunicator source, List<Friend> friends) {
        	if (source == psnCommunicator) {
        		Message.obtain(messageHandler, MESSAGE_FINISED, friends).sendToTarget();
        	}
        }

        public void onStatus(PsnCommunicator source, int resourceId) {
        	if (source == psnCommunicator) {
        		Message.obtain(messageHandler, MESSAGE_STATUS, resourceId, 0).sendToTarget();
        	}
        }

        public void onError(PsnCommunicator source, int resourceId, Throwable t) {
        	if (source == psnCommunicator) {
        		Message.obtain(messageHandler, MESSAGE_ERROR, resourceId, 0, t).sendToTarget();
        	}
        }
    }

    private class FriendAdapter extends ArrayAdapter<Friend> {

        public FriendAdapter(Context context, int textViewResourceId, List<Friend> items) {
            super(context, textViewResourceId, items);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.friend_list_row, null);
            }
            Friend friend = friendList.get(position);
            if (friend != null) {
                //Log.i(LOG_TAG, friend.toString());
                TextView tt = (TextView) v.findViewById(R.id.toptext);
                TextView bt = (TextView) v.findViewById(R.id.bottomtext);
                ImageView im = (ImageView) v.findViewById(R.id.icon);
                if (im != null) {
                    im.setImageResource(R.drawable.friend);
                    if (friend.getAvatarUrl() != null) {
                        ImageLoader.start(friend.getAvatarUrl(), im);
                    }
                }
                if (tt != null) {
                    tt.setText(friend.getOnlineId());
                }
                if (bt != null) {
                    switch (friend.getPresence()) {
                    case Online:
                        bt.setTextColor(getResources().getColor(R.color.online));
                        if (TextUtils.isEmpty(friend.getCurrentGame())) {
                            bt.setText(R.string.presence_online);
                        } else {
                            bt.setText(friend.getCurrentGame());
                        }
                        break;
                    case Away:
                        bt.setText(R.string.presence_away);
                        bt.setTextColor(getResources().getColor(R.color.away));
                        break;
                    case Offline:
                        bt.setText(TextUtil.getTimeSpanString(System.currentTimeMillis() - friend.getLastSeenTimestamp(), getContext()));
                        bt.setTextColor(getResources().getColor(R.color.offline));
                        break;
                    default:
                        bt.setText(R.string.presence_offline);
                        bt.setTextColor(getResources().getColor(R.color.offline));
                        break;
                    }
                }
            }
            return v;
        }
    }
}